// GenGtkCode.cpp : 定义控制台应用程序的入口点。
//

#ifdef WIN32
#include <io.h>
#include <direct.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <gtkui_public.h>
#include <string.h>
#include <memory.h>

#include <string>

#ifndef WIN32
#define _access access
#endif

#ifdef __cplusplus
extern "C" {
#endif

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

#ifdef __cplusplus
};
#endif

enum GTKUI_TYPE_ENUM{
    GTKUI_TYPE_ENUM_NONE = 0,
    GTKUI_TYPE_XML_DOC,
    GTKUI_TYPE_XML_NODE,
    GTKUI_TYPE_XML_ATTR,
};

typedef struct {
    GTKUI_TYPE_ENUM   type_id;    //4种类型，分别是XmlDoc, XmlNode, XmlAttr
    const char        *type_name;
    void              *ptr;
} gtkui_userdata;

#define GTKUI_check_num_args(func_name, a, b) \
    if (lua_gettop(L)<a || lua_gettop(L)>b) \
  {gtkui_Lua_pushferrstring(L,"Error in %s expected %d..%d args, got %d", func_name, a, b, lua_gettop(L));\
  goto fail;}

#define GTKUI_isptrtype(L,I) (lua_isuserdata(L,I) || lua_isnil(L,I))

#define GTKUI_fail_arg(func_name, argnum, type) \
  {gtkui_Lua_pushferrstring(L,"Error in %s (arg %d), expected '%s' got '%s'",\
                            func_name , argnum, type, gtkui_Lua_typename(L, argnum));\
  goto fail;}

static void gtkui_Lua_pushferrstring (lua_State *L, const char *fmt, ...)
{
    va_list argp;
    va_start(argp, fmt);
    luaL_where(L, 1);
    lua_pushvfstring(L, fmt, argp);
    va_end(argp);
    lua_concat(L, 2);
}

static const char *gtkui_Lua_typename(lua_State *L, int tp)
{
    gtkui_userdata *usr;
    if (lua_isuserdata(L,tp))
    {
        usr = (gtkui_userdata*)lua_touserdata(L,tp);  /* get data */
        if (usr && usr->type_id && usr->type_name)
            return usr->type_name;
        return "userdata (unknown type)";
    }
    return lua_typename(L,lua_type(L,tp));
}

static void gtkui_new_pointer_object(lua_State *L, void *ptr, GTKUI_TYPE_ENUM id, const char* name)
{
    gtkui_userdata *usr;
    if (!ptr){
        lua_pushnil(L);
        return;
    }
    usr = (gtkui_userdata*)lua_newuserdata(L,sizeof(gtkui_userdata));  /* get data */
    usr->ptr       = ptr;  /* set the ptr */
    usr->type_id   = id;
    usr->type_name = name;
}

#define GTKUI_NEW_XML_DOC(L, ptr)       gtkui_new_pointer_object(L, ptr, GTKUI_TYPE_XML_DOC,  "XmlDoc*")
#define GTKUI_NEW_XML_NODE(L, ptr)      gtkui_new_pointer_object(L, ptr, GTKUI_TYPE_XML_NODE, "XmlNode*")
#define GTKUI_NEW_XML_ATTR(L, ptr)      gtkui_new_pointer_object(L, ptr, GTKUI_TYPE_XML_ATTR, "XmlAttr*")

static const char* _gtkui_get_type_string(GTKUI_TYPE_ENUM type_id)
{
    switch (type_id)
    {
    case GTKUI_TYPE_ENUM_NONE:
        return "NONE";
    case GTKUI_TYPE_XML_DOC:
        return "XmlDoc*";
    case GTKUI_TYPE_XML_NODE:
        return "XmlNode*";
    case GTKUI_TYPE_XML_ATTR:
        return "XmlAttr*";
    }
    return "void*";
}

static int  gtkui_get_pointer_object(lua_State *L, int index, void **ptr, GTKUI_TYPE_ENUM type_id)
{
    gtkui_userdata *usr;
    if (lua_isnil(L,index)){*ptr=0; return 0;}
    usr=(gtkui_userdata*)lua_touserdata(L,index);  /* get data */
    if (usr)
    {
        if (GTKUI_TYPE_ENUM_NONE == type_id)            /* special cast void*, no casting fn */
        {
            *ptr = usr->ptr;
            return 0; /* ok */
        }
        if (type_id == usr->type_id){
            *ptr = usr->ptr;
            return 0;
        }
    }
    return -1;  /* error */
}

static void* gtk_must_pointer(lua_State *L, int index, GTKUI_TYPE_ENUM type_id,const char *func_name){
    void *result = nullptr;
    if (0 != gtkui_get_pointer_object(L,index, &result,type_id)) {
        luaL_error (L,"Error in %s, expected a %s at argument number %d\n", func_name, _gtkui_get_type_string(type_id) ,index);
    }
    return result;
}

#define GTKUI_GET_XML_DOC(L, index,  func_name)     gtk_must_pointer(L, index, GTKUI_TYPE_XML_DOC,      func_name)
#define GTKUI_GET_XML_NODE(L, index, func_name)     gtk_must_pointer(L, index, GTKUI_TYPE_XML_NODE,     func_name)
#define GTKUI_GET_XML_ATTR(L, index, func_name)     gtk_must_pointer(L, index, GTKUI_TYPE_XML_ATTR,     func_name)

static int lua_get_gtk_ui_root(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_root",1,1)
  if(!GTKUI_isptrtype(L,1))
      GTKUI_fail_arg("get_gtk_ui_root",1, "XmlDoc *");
  arg1 = GTKUI_GET_XML_DOC(L,1,"get_gtk_ui_root");
  result = (void *)get_gtk_ui_root(arg1);
  GTKUI_NEW_XML_NODE(L, result);
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static int lua_get_gtk_ui_first_child(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  void *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_first_child",2,2)
  if(!GTKUI_isptrtype(L,1))
      GTKUI_fail_arg("get_gtk_ui_first_child",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L,2))
      GTKUI_fail_arg("get_gtk_ui_first_child",2,"XmlNode *");
  arg1=(void *)GTKUI_GET_XML_DOC(L,1,"get_gtk_ui_first_child");
  arg2=(void *)GTKUI_GET_XML_NODE(L,2,"get_gtk_ui_first_child");
  result = (void *)get_gtk_ui_first_child(arg1,arg2);
  GTKUI_NEW_XML_NODE(L,result);
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}


static int lua_get_gtk_ui_next_child(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  void *arg3 = (void *) 0 ;
  void *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_next_child", 3, 3)
  if(!GTKUI_isptrtype(L,1)) 
      GTKUI_fail_arg("get_gtk_ui_next_child", 1,"XmlDoc *");
  if(!GTKUI_isptrtype(L,2)) 
      GTKUI_fail_arg("get_gtk_ui_next_child", 3,"XmlNode *");
  if(!GTKUI_isptrtype(L,3)) 
      GTKUI_fail_arg("get_gtk_ui_next_child", 3,"XmlNode *");
  arg1 = (void *)GTKUI_GET_XML_DOC(L,  1, "get_gtk_ui_next_child");
  arg2 = (void *)GTKUI_GET_XML_NODE(L, 2, "get_gtk_ui_next_child");
  arg3 = (void *)GTKUI_GET_XML_NODE(L, 3, "get_gtk_ui_next_child");
  result = (void *)get_gtk_ui_next_child(arg1, arg2, arg3);
  GTKUI_NEW_XML_NODE(L,result); 
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static int lua_get_gtk_ui_parent(lua_State* L) {
    int gtkui_arg = 0;
    void *arg1 = (void *) 0 ;
    void *arg2 = (void *) 0 ;
    void *result = 0 ;
    
    GTKUI_check_num_args("lua_get_gtk_ui_parent",2,2)
    if(!GTKUI_isptrtype(L,1))
        GTKUI_fail_arg("lua_get_gtk_ui_parent",1,"XmlDoc *");
    if(!GTKUI_isptrtype(L,2))
        GTKUI_fail_arg("lua_get_gtk_ui_parent",2,"XmlNode *");
    arg1=(void *)GTKUI_GET_XML_DOC(L,1,"lua_get_gtk_ui_parent");
    arg2=(void *)GTKUI_GET_XML_NODE(L,2,"lua_get_gtk_ui_parent");
    result = (void *)get_gtk_ui_parent(arg1,arg2);
    GTKUI_NEW_XML_NODE(L, result);
    gtkui_arg++; 
    return gtkui_arg;
    
  fail:
    lua_error(L);
    return gtkui_arg;
  }
  
static int lua_get_gtk_ui_has_child(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  const char *arg3 = 0 ;
  int result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_has_child", 3, 3)
  if(!GTKUI_isptrtype(L, 1))
      GTKUI_fail_arg("get_gtk_ui_has_child", 1,"XmlDoc *");
  if(!GTKUI_isptrtype(L, 2))
      GTKUI_fail_arg("get_gtk_ui_has_child", 2,"XmlNode *");
  if(!lua_isstring(L, 3))
      GTKUI_fail_arg("get_gtk_ui_has_child", 3, "string");
  arg1 = (void *)GTKUI_GET_XML_DOC(L,  1, "get_gtk_ui_has_child");
  arg2 = (void *)GTKUI_GET_XML_NODE(L, 2, "get_gtk_ui_has_child");
  arg3 = lua_tostring(L, 3);
  result = (int)get_gtk_ui_has_child_node(arg1, arg2, arg3);
  lua_pushboolean(L, result);
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static int lua_get_gtk_ui_node_name(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  char *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_node_name",2,2)
  if(!GTKUI_isptrtype(L,1)) 
      GTKUI_fail_arg("get_gtk_ui_node_name",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L,2)) 
      GTKUI_fail_arg("get_gtk_ui_node_name",2,"XmlNode *");
  arg1=(void *)GTKUI_GET_XML_DOC(L,1,"get_gtk_ui_node_name");
  arg2=(void *)GTKUI_GET_XML_NODE(L,2,"get_gtk_ui_node_name");
  result = (char *)get_gtk_ui_node_name(arg1, arg2);
  lua_pushstring(L,(const char *)result);
  gtkui_arg++;
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}


static int lua_get_gtk_ui_node_value(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  char *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_node_value",2,2)
  if(!GTKUI_isptrtype(L,1)) 
      GTKUI_fail_arg("get_gtk_ui_node_value",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L,2)) 
      GTKUI_fail_arg("get_gtk_ui_node_value",2,"XmlNode *");
  arg1=(void *)GTKUI_GET_XML_DOC(L,1,"get_gtk_ui_node_value");
  arg2=(void *)GTKUI_GET_XML_NODE(L,2,"get_gtk_ui_node_value");
  result = (char *)get_gtk_ui_node_value(arg1, arg2);
  lua_pushstring(L,(const char *)result); 
  gtkui_arg++;
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static int lua_get_gtk_ui_get_child(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  const char *arg3 = 0 ;
  void *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_get_child", 3, 3)
  if(!GTKUI_isptrtype(L, 1))
      GTKUI_fail_arg("get_gtk_ui_get_child", 1,"XmlDoc *");
  if(!GTKUI_isptrtype(L, 2))
      GTKUI_fail_arg("get_gtk_ui_get_child", 2,"XmlNode *");
  if(!lua_isstring(L, 3))
      GTKUI_fail_arg("get_gtk_ui_get_child", 3,"string");
  arg1 = (void *)GTKUI_GET_XML_DOC(L,  1, "get_gtk_ui_get_child");
  arg2 = (void *)GTKUI_GET_XML_NODE(L, 2, "get_gtk_ui_get_child");
  arg3 = lua_tostring(L, 3);
  result = (void *)get_gtk_ui_get_child_node(arg1, arg2, arg3);
  GTKUI_NEW_XML_NODE(L,result);
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static int gtkui_isnilstring(lua_State *L, int idx) {
    int ret = lua_isstring(L, idx);
    if (!ret)
        ret = lua_isnil(L, idx);
    return ret;
}

static int lua_get_gtk_ui_first_property(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  void *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_first_property",2,2)
  if(!GTKUI_isptrtype(L,1))
      GTKUI_fail_arg("get_gtk_ui_first_property",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L,2))
      GTKUI_fail_arg("get_gtk_ui_first_property",2,"XmlNode *");
  arg1=(void *)GTKUI_GET_XML_DOC(L,1,"get_gtk_ui_first_property");
  arg2=(void *)GTKUI_GET_XML_NODE(L,2,"get_gtk_ui_first_property");
  result = (void *)get_gtk_ui_first_property(arg1, arg2);
  GTKUI_NEW_XML_ATTR(L, result);
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}


static int lua_get_gtk_ui_next_property(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  void *arg3 = (void *) 0 ;
  void *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_next_property", 3, 3)
  if(!GTKUI_isptrtype(L,1)) 
      GTKUI_fail_arg("get_gtk_ui_next_property",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L,2)) 
      GTKUI_fail_arg("get_gtk_ui_next_property",2,"XmlNode *");
  if(!GTKUI_isptrtype(L,3)) 
      GTKUI_fail_arg("get_gtk_ui_next_property",3,"XmlAttr *");
  arg1=(void *)GTKUI_GET_XML_DOC(L,1, "get_gtk_ui_next_property");
  arg2=(void *)GTKUI_GET_XML_NODE(L, 2,"get_gtk_ui_next_property");
  arg3=(void *)GTKUI_GET_XML_ATTR(L, 3, "get_gtk_ui_next_property");
  result = (void *)get_gtk_ui_next_property(arg1, arg2, arg3);
  GTKUI_NEW_XML_ATTR(L,result); 
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static int lua_get_gtk_ui_has_property(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  const char *arg3 = 0 ;
  int result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_has_property", 3, 3)
  if(!GTKUI_isptrtype(L, 1))
      GTKUI_fail_arg("get_gtk_ui_has_property",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L, 2))
      GTKUI_fail_arg("get_gtk_ui_has_property",2,"XmlNode *");
  if(!lua_isstring(L, 3))
      GTKUI_fail_arg("get_gtk_ui_has_property", 3, "string");
  arg1 = (void *)GTKUI_GET_XML_DOC(L,  1, "get_gtk_ui_has_property");
  arg2 = (void *)GTKUI_GET_XML_NODE(L, 2, "get_gtk_ui_has_property");
  arg3 = lua_tostring(L, 3);
  result = get_gtk_ui_has_property(arg1, arg2, (const char*)arg3);
  lua_pushboolean(L, result);
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static int lua_get_gtk_ui_get_property(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  const char *arg3 = 0 ;
  void *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_get_property", 3, 3)
  if(!GTKUI_isptrtype(L, 1))
      GTKUI_fail_arg("get_gtk_ui_get_property", 1,"XmlDoc *");
  if(!GTKUI_isptrtype(L, 2))
      GTKUI_fail_arg("get_gtk_ui_get_property", 2,"XmlNode *");
  if(!lua_isstring(L, 3))
      GTKUI_fail_arg("get_gtk_ui_get_property", 3, "string");
  arg1 = (void *)GTKUI_GET_XML_DOC(L,  1, "get_gtk_ui_get_property");
  arg2 = (void *)GTKUI_GET_XML_NODE(L, 2, "get_gtk_ui_get_property");
  arg3 = lua_tostring(L, 3);
  result = (void *)get_gtk_ui_get_property(arg1, arg2, (const char*)arg3);
  GTKUI_NEW_XML_ATTR(L, result); 
  gtkui_arg++; 
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}


static int lua_get_gtk_ui_property_name(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  void *arg3 = (void *) 0 ;
  char *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_property_name", 3, 3)
  if(!GTKUI_isptrtype(L, 1)) 
      GTKUI_fail_arg("get_gtk_ui_property_name",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L, 2)) 
      GTKUI_fail_arg("get_gtk_ui_property_name",2,"XmlNode *");
  if(!GTKUI_isptrtype(L, 3)) 
      GTKUI_fail_arg("get_gtk_ui_property_name",3,"XmlAttr *");
  arg1=(void *)GTKUI_GET_XML_DOC(L,  1, "get_gtk_ui_property_name");
  arg2=(void *)GTKUI_GET_XML_NODE(L, 2, "get_gtk_ui_property_name");
  arg3=(void *)GTKUI_GET_XML_ATTR(L, 3, "get_gtk_ui_property_name");
  result = (char *)get_gtk_ui_property_name(arg1, arg2, arg3);
  lua_pushstring(L, (const char *)result);
  gtkui_arg++;
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}


static int lua_get_gtk_ui_property_value(lua_State* L) {
  int gtkui_arg = 0;
  void *arg1 = (void *) 0 ;
  void *arg2 = (void *) 0 ;
  void *arg3 = (void *) 0 ;
  char *result = 0 ;
  
  GTKUI_check_num_args("get_gtk_ui_property_value", 3, 3)
  if(!GTKUI_isptrtype(L,1)) 
      GTKUI_fail_arg("get_gtk_ui_property_value",1,"XmlDoc *");
  if(!GTKUI_isptrtype(L,2)) 
      GTKUI_fail_arg("get_gtk_ui_property_value",2,"XmlNode *");
  if(!GTKUI_isptrtype(L,3)) 
      GTKUI_fail_arg("get_gtk_ui_property_value",3,"XmlAttr *");
  arg1=(void *)GTKUI_GET_XML_DOC(L,1,"get_gtk_ui_property_value");
  arg2=(void *)GTKUI_GET_XML_NODE(L,2,"get_gtk_ui_property_value");
  arg3=(void *)GTKUI_GET_XML_ATTR(L, 3, "get_gtk_ui_property_value");
  result = (char *)get_gtk_ui_property_value(arg1, arg2, arg3);
  lua_pushstring(L,(const char *)result); 
  gtkui_arg++;
  return gtkui_arg;
  
fail:
  lua_error(L);
  return gtkui_arg;
}

static luaL_Reg gtkui_lua_method[]= {
    { "get_gtk_ui_root",            lua_get_gtk_ui_root},
    { "get_gtk_ui_first_child",     lua_get_gtk_ui_first_child},
    { "get_gtk_ui_next_child",      lua_get_gtk_ui_next_child},

    { "get_gtk_ui_parent",          lua_get_gtk_ui_parent},

    { "get_gtk_ui_has_child",       lua_get_gtk_ui_has_child},
    { "get_gtk_ui_get_child",       lua_get_gtk_ui_get_child},

    { "get_gtk_ui_node_name",       lua_get_gtk_ui_node_name},
    { "get_gtk_ui_node_value",      lua_get_gtk_ui_node_value},

    { "get_gtk_ui_first_property",  lua_get_gtk_ui_first_property},
    { "get_gtk_ui_next_property",   lua_get_gtk_ui_next_property},

    { "get_gtk_ui_has_property",    lua_get_gtk_ui_has_property},
    { "get_gtk_ui_get_property",    lua_get_gtk_ui_get_property},

    { "get_gtk_ui_property_name",   lua_get_gtk_ui_property_name},
    { "get_gtk_ui_property_value",  lua_get_gtk_ui_property_value},
    { nullptr, nullptr}
};

#if (defined _WIN64 || defined WIN64 || defined _WIN32 || defined WIN32 || defined WINCE)
#define GEN_GTK_CODE_EXE "GenGtkCode.exe"
#else
#define GEN_GTK_CODE_EXE "GenGtkCode"
#endif

static void print_usage()
{
    fprintf(stderr, "\nUsage:\n  " GEN_GTK_CODE_EXE " <lua_script_folder> <gtk_ui_file> <template_file> <output_folder> [options]\n\n");
    fprintf(stderr, "  options:\n");
    fprintf(stderr, "    --main-widget=[Main widget id]    this widget will be call at app start.\n");
    fprintf(stderr, "    --app-name=[App name]             The app name is used to create a class that aggregates all top-level widgets\n");
    fprintf(stderr, "    --project-id=[Project ID File]    The project ID file is generated by the tool [scan_template_ui.lua]\n");
    fprintf(stderr, "                                      and aggregates all top-level controls of a project (along with their type information). \n");
    fprintf(stderr, "                                      It also includes other code processing sections, such as those related to template classes.\n\n");
}

static bool file_exist(const char* file_name)
{
    if( (_access(file_name, 0 )) != -1 ){
        return true;
    }
    return false;
}

static bool folder_exist(const char* folder_name)
{
    struct stat Stat_= {0};
    if( (stat(folder_name, &Stat_) == 0 &&(Stat_.st_mode & S_IFDIR) )){
        return true;
    }
    return false;
}

static void make_directory(const char* name)
{
#if (defined _WIN64 || defined WIN64 || defined _WIN32 || defined WIN32 || defined WINCE)
    _mkdir(name);
#else
    mkdir(name, 777); 
#endif
}

static void print_lua_error_msg(lua_State* L, const char* msg)
{
    fprintf(stderr, "\nFATAL ERROR:\n  %s: %s\n\n",
        msg, lua_tostring(L, -1));
}

static int dolibrary (lua_State *L, const char *name) {
    int status;
    lua_getglobal(L, "require");
    lua_pushstring(L, name);
    status = lua_pcall(L, 1, 1, 0);
    if (status == LUA_OK)
        lua_setglobal(L, name);  /* global[name] = require return */
    return status;
}

static bool add_package_path(lua_State *L, const char* path)
{
    lua_getglobal( L, "package");
    lua_getfield( L, -1, "path"); // get field "path" from table at top of stack (-1)
    const char* old_path = lua_tostring( L, -1 ); // grab path string from top of stack
    std::string full_path = path; // %s?.lua;%s?/init.lua;
    full_path.append("/?.lua;");
    full_path.append(path);
#if (defined _WIN64 || defined WIN64 || defined _WIN32 || defined WIN32 || defined WINCE)
    full_path.append("/?.dll;");
    full_path.append(path);
#else
    full_path.append("/?.so;");
    full_path.append(path);
#endif
    full_path.append("/?/init.lua;");
    full_path.append( old_path );
    lua_pop( L, 1 ); // get rid of the string on the stack we just pushed on line 5
    lua_pushstring( L, full_path.c_str() ); // push the new one
    lua_setfield( L, -2, "path" ); // set the field "path" in table at -2 with value at top of stack
    lua_pop( L, 1 ); // get rid of package table from top of stack
    return true;
}

void print_stacknum(const char * desc, const int count)
{
    printf("%s stack num = %d\n",desc, count);
}

// 仅比较前strlen(src)个字符
int short_strcmp(const char *src, const char *dest)
{
    return strncmp(src, dest, strlen(src));
}

int main(int argc, char* argv[])
{
    // 检查参数个数
    if (argc < 5)
    {
        printf("missing paramters.\n");
        print_usage();
        return -1;
    }
    const char* script_path = argv[1];

    //检查脚本目录是否存在
    if( !(folder_exist(script_path)) ){
        printf("lua folder not exist[%s]!\n", script_path);
        print_usage();
        return -2;
    }

    const char* ui_file = argv[2];
    //检查模板目录是否存在
    if( !(file_exist(argv[2]))){
        printf("ui folder not exist[%s]!\n", ui_file);
        print_usage();
        return -3;
    }

    const char* templ_file = argv[3];
    //检查文件是否存在
    if( !file_exist(argv[3]) ){
        printf("template file not exist[%s]!\n", templ_file);
        return -4;
    }

    const char* dest_folder = argv[4];
    //检查目标目录是否存在
    if( (folder_exist(dest_folder))){
        printf("dest folder exist, will overwrite it!\n");
    } else {
        make_directory(dest_folder);
    }

    // 检查参数个数
    const char* app_name = NULL;
    const char* main_widget = NULL;
    const char* project_id_list = NULL;
    const char* gtk_version = NULL;
    const char* def_gtk_version = "224";
    char gtk_temp_name[32] = {0};
    if (argc > 5)
    {
        // 支持--app-name --main-widget --project-id三个参数的判断
        for (int i = 5; i < argc; i++)
        {
            if (short_strcmp("--app-name=", argv[i]) == 0)
            {
                app_name = &(argv[i][sizeof("--app-name=") - 1]);
            }
            else if (short_strcmp("--main-widget=", argv[i]) == 0)
            {
                main_widget = &(argv[i][sizeof("--main-widget=" - 1)]);
            }
            else if (short_strcmp("--project-id=", argv[i]) == 0)
            {
                project_id_list = &(argv[i][sizeof("--project-id=") - 1]);
            }
            else if (short_strcmp("--gtk-ver=", argv[i]) == 0)
            {
                gtk_version = &(argv[i][sizeof("--gtk-ver=") - 1]);
            }
        }
    }

    // 开始
    lua_State* L = luaL_newstate();
    if (L == NULL) {
        printf("cannot create state: not enough memory");
        return -5;
    }

    // xml方式加载ui文件
    void* xml_doc = load_gtk_ui(ui_file);
    if (nullptr == xml_doc) {
        printf("load ui file fail!\n");
        lua_close(L);
        return -6;
    }

    // 加载默认库
    luaL_openlibs(L);

    // 注册当前函数
    lua_pushglobaltable(L);
    luaL_setfuncs(L, gtkui_lua_method, 0);//sizeof(gtkui_lua_method)/sizeof(luaL_Reg));

    // 开始加载
    uint32_t ret = -1;
    do 
    {
        // 添加argv[2]至package路径
        if (!add_package_path(L, script_path)){
            printf("add_package_path fail!\n");
            print_lua_error_msg(L, "add_package_path");
            break;
        }

        // 调试LUA脚本时使用 LuaPanda
#ifdef DEBUG_LUA
        // 加载socket.core
        if (LUA_OK != dolibrary(L, "socket.core")) {
            printf("load socket.core fail!\n");
            print_lua_error_msg(L, "dolibrary");
            break;
        }
        // 加载LuaPanda
        if (LUA_OK != dolibrary(L, "LuaPanda")) {
            printf("load LuaPanda fail!\n");
            print_lua_error_msg(L, "dolibrary");
            break;
        }
        // 通过名字获取模块
        lua_getglobal(L, "LuaPanda");
        if(!lua_istable(L, -1) ){
            printf("Get LuaPanda table fail!\n");
            print_lua_error_msg(L, "get LuaPanda");
            break;
        }
        // 获取模块下的函数
        lua_getfield(L, -1, "start");
        // 判断是否是函数
        if(!lua_isfunction(L, -1) ){
            printf("Get LuaPanda start fail!\n");
            print_lua_error_msg(L, "get start");
            break;
        }
        // 构建参数1
        lua_pushstring(L, "127.0.0.1");
        // 构造参数2
        lua_pushstring(L, "8818");
        // 执行
        auto status1 = lua_pcall(L,  2,  0, 0);
        if (status1 != LUA_OK) {
            printf("Execute lua start function fail!\n");
            print_lua_error_msg(L, "exec start");
            break;
        }
#endif
        // 加载文件
        if (LUA_OK != dolibrary(L, "GenGtkCode")) {
            printf("Load lua GenGtkCode fail!\n");
            print_lua_error_msg(L, "load GenGtkCode");
            break;
        }
        // 判断名称是否是自动获取，
        if (gtk_version != NULL) {
            // 拷贝名称
        	memcpy(gtk_temp_name, gtk_version, sizeof(gtk_temp_name));
            // 转换成小写
            for (int i = 0; i < strlen(gtk_temp_name); i++)
            {
                gtk_temp_name[i] = tolower(gtk_temp_name[i]);
            }
            // 比较是否是auto
            if (short_strcmp("auto", gtk_temp_name) == 0) {
                // 获取函数
                lua_getglobal(L,  "get_gtk_version_from_xml");
                // 多重判断，包装在do while中
                do {
                    if(!lua_isfunction(L, -1) ){
                        printf("Execute lua get_gtk_version_from_xml function fail!\n");
                        print_lua_error_msg(L, "get get_gtk_version_from_xml");
                        // 使用默认版本
                        gtk_version = NULL;
                        break;
                    }
                    // 构建第一个参数，UI文件对象
                    GTKUI_NEW_XML_DOC(L, xml_doc);
                    // 第二个参数，默认版本号参数
                    lua_pushstring(L, def_gtk_version);
                    // 执行
                    auto status = lua_pcall(L,  2,  1, 0);
                    // 判断返回值
                    if (status != LUA_OK) {
                        printf("Execute lua function fail!\n");
                        print_lua_error_msg(L, "exec get_gtk_version_from_xml");
                        // 使用默认版本
                        gtk_version = NULL;
                        break;
                    }
                    // 获取返回值
                    if (lua_isnil(L, -1)) {
                        printf("get_gtk_version_from_xml return nil!\n");
                        // 使用默认版本
                        gtk_version = NULL;
                        break;
                    }
                    // 判断是否是字符串
                    if (!lua_isstring(L, -1))
                    {
                        printf("get_gtk_version_from_xml return non-string[%d]!\n", lua_type(L, -1));
                        // 使用默认版本
                        gtk_version = NULL;
                        break;
                    }
                    // 获取版本号
                    gtk_version = lua_tostring(L, -1);
                    // 检查是否为空
                    if (gtk_version == NULL) {
                        printf("get_gtk_version_from_xml return NULL!\n");
                        break;
                    }
                    printf("[INFO] get_gtk_version_from_xml return [%s]!\n", gtk_version);
                } while(0);
            }
        }

        // 在使用前，保证版本号字符串永远不为NULL
        if (gtk_version == NULL) {
            gtk_version = def_gtk_version;
        }
        // 加载pango224
        snprintf(gtk_temp_name, sizeof(gtk_temp_name), "pango%s", gtk_version);
        if (LUA_OK != dolibrary(L, gtk_temp_name)) {
            printf("load %s fail!\n", gtk_temp_name);
            print_lua_error_msg(L, "dolibrary");
            break;
        }
        // 加载gdk224
        snprintf(gtk_temp_name, sizeof(gtk_temp_name), "gdk%s", gtk_version);
        if (LUA_OK != dolibrary(L, gtk_temp_name)) {
            printf("load %s fail!\n", gtk_temp_name);
            print_lua_error_msg(L, "dolibrary");
            break;
        }
        // 加载gtk224
        snprintf(gtk_temp_name, sizeof(gtk_temp_name), "gtk%s", gtk_version);
        if (LUA_OK != dolibrary(L, gtk_temp_name)) {
            printf("load %s fail!\n", gtk_temp_name);
            print_lua_error_msg(L, "dolibrary");
            break;
        }
        // 调用如下代码，实现lua如下功能 Gtk = Gtk224
        snprintf(gtk_temp_name, sizeof(gtk_temp_name), "Gtk = Gtk%s", gtk_version);
        if (LUA_OK != luaL_dostring(L, gtk_temp_name)) {
            printf("do [%s] fail!\n", gtk_temp_name);
            print_lua_error_msg(L, "dostring");
            break;
        }
        // 获取主函数
        lua_getglobal(L,  "gen_gtk_code");
        if(!lua_isfunction(L, -1) ){
            printf("Execute lua gen_gtk_code function fail!\n");
            print_lua_error_msg(L, "get gen_gtk_code");
            break;
        }

        // 构建第一个参数，UI文件对象
        GTKUI_NEW_XML_DOC(L, xml_doc);
        // 第二个参数，模板文件，
        lua_pushstring(L, templ_file);
        // 第三个参数，目标文件夹
        lua_pushstring(L, dest_folder);
        // 第四个参数，project_id_list
        if (project_id_list != NULL) {
            lua_pushstring(L, project_id_list);
        } else {
            lua_pushnil(L);
        }
        // 第五个参数，main_widget
        if (main_widget != NULL) {
            lua_pushstring(L, main_widget);
        } else {
            lua_pushnil(L);
        }
        // 第六个参数，main_widget
        if (app_name != NULL) {
            lua_pushstring(L, app_name);
        } else {
            lua_pushnil(L);
        }
        // 执行
        auto status = lua_pcall(L,  6,  0, 0);
        if (status != LUA_OK) {
            printf("Execute lua function fail!\n");
            print_lua_error_msg(L, "exec gen_gtk_code");
            break;
        }
        ret = 0;
    } while (0);

    // 关闭句柄，释放资源
    lua_close(L);

    release_gtk_ui(xml_doc);

	return ret;
}

